﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using System.Net;
using TweetMyApps.Properties;
using Twitterizer.Framework;
using System.ComponentModel;
using System.Collections;
using System.Deployment.Application;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;

namespace TweetMyApps
{
    public partial class FormTweetMyApps : Form
    {

        private bool _closing = false;
        private Dictionary<string, ListViewGroup> Groups = new Dictionary<string, ListViewGroup>();
        private readonly AppInfos _appInfos = new AppInfos();
        private string _dataDirectory = "./";
        private const int REFRESH_INTERVAL = 5;
        private DateTime _cachedUsageLastUpdate = DateTime.MinValue;
        private IWebProxy _proxy;
        private ApplicationDeployment _appDeployement = null;
        private FormProgressBar frmProgressBar = null;

        private const string APPINFO_DB = "AppInfo.db";
        private const string APPINFOWEB_DB = "AppInfoWeb.db";
        private const string URL = "http://download.tiptoptool.com/Web/TweetMyApps/";
        private const string URL_VERSION = URL + "/version.php";
        private const string URL_APPINFO_DB = URL + APPINFOWEB_DB + ".php";
        public string ProductUrl
        {
            get
            {
                object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
                if (attributes.Length == 1)
                {
                    return ((AssemblyDescriptionAttribute)attributes[0]).Description;
                }
                return string.Empty;
            }
        }

        #region Windows API Functions Declarations
        //This Function is used to get Active Window Title...
        [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        public static extern int GetWindowText(IntPtr hwnd, string lpString, int cch);

        //This Function is used to get Handle for Active Window...
        [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        private static extern IntPtr GetForegroundWindow();

        //This Function is used to get Active process ID...
        [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 lpdwProcessId);


        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SystemParametersInfo(int uAction,
        int uParam, ref int lpvParam, int fuWinIni);

        private bool IsScreenSaverRunning()
        {
            const int SPI_GETSCREENSAVERRUNNING = 114;
            int screenSaverRunning = -1;

            // is the screen saver running?
            int ok = SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref screenSaverRunning, 0);

            if (ok == 0 || screenSaverRunning == 0)
                return false;
            return true;
        }

        public static string GetActiveApplicationTitle()
        {
            try
            {
                //This method is used to get active application's title using GetWindowText() method present in user32.dll
                IntPtr hwnd = GetForegroundWindow();
                if (hwnd.Equals(IntPtr.Zero)) return "Unknown";
                string lpText = new string((char)0, 300);
                int intLength = GetWindowText(hwnd, lpText, lpText.Length);
                lpText = lpText.Trim('\0').Trim();
                if (lpText.Length <= 0) return "Unknown";
                return lpText.Trim();
            }
            catch { return "Unknown"; }
        }

        public static string GetActiveApplicationFileName()
        {
            Int32 pid;
            try
            {
                IntPtr hwnd = GetForegroundWindow();
                GetWindowThreadProcessId(hwnd, out pid);
                Process p = Process.GetProcessById(pid);
                return p.ProcessName;
            }
            catch { return "Unknown"; }
        }

        #endregion

        public FormTweetMyApps()
        {
            InitializeComponent();
            toolStripComboBoxMinimumUsageThreshold.Items.Clear();
            toolStripComboBoxMinimumUsageThreshold.Items.Add(new Duration(0));
            toolStripComboBoxMinimumUsageThreshold.Items.Add(new Duration(30));
            toolStripComboBoxMinimumUsageThreshold.Items.Add(new Duration(60));
            toolStripComboBoxMinimumUsageThreshold.Items.Add(new Duration(2 * 60));
            toolStripComboBoxMinimumUsageThreshold.Items.Add(new Duration(5 * 60));
            toolStripComboBoxMinimumUsageThreshold.Items.Add(new Duration(10 * 60));
            toolStripComboBoxMinimumUsageThreshold.Items.Add(new Duration(15 * 60));

            if (ApplicationDeployment.IsNetworkDeployed)
                _appDeployement = ApplicationDeployment.CurrentDeployment;
            // Vista and 7
            if (Environment.OSVersion.Version.Major > 5)
                this.notifyIcon.Icon = Resources.TweetMyAppsIconAllSizes;
            else // 2000/XP
                this.notifyIcon.Icon = Resources.TweetMyAppsIcon16;
            this.notifyIcon.Visible = true;
            this.notifyIcon.MouseMove += new System.Windows.Forms.MouseEventHandler(this.notifyIcon_MouseMove);
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                _appDeployement.CheckForUpdateProgressChanged += new DeploymentProgressChangedEventHandler(appDeployement_CheckForUpdateProgressChanged);
                _appDeployement.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(appDeployement_CheckForUpdateCompleted);
                _appDeployement.UpdateProgressChanged += new DeploymentProgressChangedEventHandler(appDeployement_UpdateProgressChanged);
                _appDeployement.UpdateCompleted += new AsyncCompletedEventHandler(appDeployement_UpdateCompleted);
            }
        }

        #region General UI

        private void FormTweetMyApps_Load(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            listViewUsage.ListViewItemSorter = (IComparer)new AppInfoComparer();
            LoadSettings();
            _appInfos.Load(Path.Combine(_dataDirectory, APPINFO_DB));
            if (Settings.Default.AutoUpdateDBOnStart)
                GetUpdateAppInfoDB();
            BindListView();
            RefreshUsageResult();
            Cursor.Current = Cursors.Default;

        }

        private void txtTwitterLogin_TextChanged(object sender, EventArgs e)
        {
            txtTwitterLogin.Tag = "changed";
        }

        private void txtTwitterPassword_TextChanged(object sender, EventArgs e)
        {
            txtTwitterPassword.Tag = "changed";
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _closing = true;
            this.Close();
        }

        private void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            viewUsageToolStripMenuItem_Click(sender, e);
        }

        private void viewUsageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Show();
            WindowState = FormWindowState.Normal;
            this.Activate();
            RefreshUsageResult(true);
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new TipTopToolAboutBox().ShowDialog();
        }

        private void FormTweetMyApps_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing && !_closing)
            {
                e.Cancel = true;
                this.WindowState = FormWindowState.Minimized;
                this.Hide();
            }
            SaveAll();
        }

        private void FormTweetMyApps_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                this.Hide();
            }
            else if (showInTaskBarToolStripMenuItem.Checked)
                this.ShowInTaskbar = true;

        }

        #endregion

        #region CheckForUpdate
        private void checkForUpdateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                    ClickOnceCheckForUpdateAsync(false);
                else
                {
                    Cursor.Current = Cursors.WaitCursor;
                    HttpWebRequest request = Utils.CreateHttpWebRequest(URL_VERSION, ProductName + " " + ProductVersion, _proxy);
                    using (WebResponse response = request.GetResponse())
                    {
                        using (StreamReader sr = new StreamReader(response.GetResponseStream()))
                        {
                            string version = sr.ReadLine();
                            if (!string.IsNullOrEmpty(version))
                            {
                                Version lastVersion = new Version(version);
                                if (new Version(ProductVersion) < lastVersion)
                                {
                                    Cursor.Current = Cursors.Default;
                                    if (MessageBox.Show("A new version of " + ProductName + " is available : " + lastVersion + "\r\n"
                                        + "Do you want to download this version ?", ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                                    {
                                        Cursor.Current = Cursors.WaitCursor;
                                        Process.Start(ProductUrl);
                                        Cursor.Current = Cursors.Default;
                                    }

                                }
                                else
                                {
                                    Cursor.Current = Cursors.Default;
                                    MessageBox.Show("You have the latest version of " + ProductName, ProductName);
                                }
                            }
                            sr.Close();
                        }
                        response.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("This application cannot be updated.\r\nError: " + ex.Message, ProductName);
            }
            Cursor.Current = Cursors.Default;
        }

        private void timerCheckForUpdate_Tick(object sender, EventArgs e)
        {
            //after first check (3min), check every 6hr
            timerCheckForUpdate.Interval = 6 * 60 * 60 * 1000;
            ClickOnceCheckForUpdateAsync(true);
        }

        private void ClickOnceCheckForUpdateAsync(bool silent)
        {
            try
            {
                if (!silent)
                {
                    Cursor.Current = Cursors.WaitCursor;
                    frmProgressBar = new FormProgressBar("Check for update...", "Checking for update...", true);
                    frmProgressBar.Show();
                }
                if (_appDeployement != null)
                    _appDeployement.CheckForUpdateAsync();
            }
            catch (DeploymentDownloadException dde)
            {
                if (!silent)
                {
                    if (frmProgressBar != null) frmProgressBar.Close();
                    frmProgressBar = null;
                    Cursor.Current = Cursors.Default;
                    MessageBox.Show("The new version of the application cannot be downloaded at this time.\r\nPlease check your network connection, or try again later. Error: " + dde.Message, ProductName);
                }
                return;
            }
            catch (InvalidOperationException ioe)
            {
                if (!silent)
                {
                    if (frmProgressBar != null) frmProgressBar.Close();
                    frmProgressBar = null;
                    Cursor.Current = Cursors.Default;
                    MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message, ProductName);
                }
                return;
            }
            catch (InvalidDeploymentException ide)
            {
                if (!silent)
                {
                    if (frmProgressBar != null) frmProgressBar.Close();
                    frmProgressBar = null;
                    Cursor.Current = Cursors.Default;
                    MessageBox.Show("Cannot check for a new version of the application. The ClickOnce may be corrupted.\r\nPlease send to the support the following error message.\r\nError: " + ide.Message, ProductName);
                }
                return;
            }
            catch (Exception ex)
            {
                if (!silent)
                {
                    if (frmProgressBar != null) frmProgressBar.Close();
                    frmProgressBar = null;
                    Cursor.Current = Cursors.Default;
                    MessageBox.Show("Cannot check for a new version of the application. The ClickOnce may be corrupted.\r\nPlease send to the support the following error message.\r\nError: " + ex.Message, ProductName);
                }
                return;
            }
        }

        void appDeployement_CheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
        {
            if (frmProgressBar != null)
            {
                frmProgressBar.ProgressChanged("Checking for update...", e.ProgressPercentage);
            }
        }

        void appDeployement_CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e)
        {
            Cursor.Current = Cursors.Default;
            if (e.UpdateAvailable)
            {
                string updateNotificationMessage = "You are currently using " + ProductName + " version " + ProductVersion + ".\r\n"
                        + "A new version is available (" + e.AvailableVersion + ").\r\n"
                        + "(approximated download size: " + (int)(e.UpdateSizeBytes / 1024) + " KB)" + "\r\n\r\n";
                // silent mode
                if (frmProgressBar == null)
                {
                    notifyIcon.ShowBalloonTip(5000, ProductName, updateNotificationMessage
                        + "Click here to update the application now ?\r\n", ToolTipIcon.Info);
                }
                else
                {
                    if (frmProgressBar != null)
                    {
                        frmProgressBar.Close();
                        frmProgressBar = null;
                    }
                    if (MessageBox.Show(updateNotificationMessage
                        + "Would you like to update the application now ?\r\n"
                        , ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                        ClickOnceDoUpdate();
                }
            }
            else
            {
                if (frmProgressBar != null)
                {
                    frmProgressBar.Close();
                    frmProgressBar = null;
                    MessageBox.Show("You have the latest version of " + ProductName, ProductName);
                }
            }
        }

        private void ClickOnceDoUpdate()
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                frmProgressBar = new FormProgressBar("Check for update...", "Updating " + ProductName + "...", true);
                frmProgressBar.Show();
                _appDeployement.UpdateAsync();
            }
            catch (DeploymentDownloadException dde)
            {
                if (frmProgressBar != null) frmProgressBar.Close();
                frmProgressBar = null;
                Cursor.Current = Cursors.Default;
                MessageBox.Show("Cannot install the latest version of the application.\r\nPlease check your network connection, or try again later. Error: " + dde, ProductName);
            }
        }

        void notifyIcon_BalloonTipClicked(object sender, EventArgs e)
        {
            ClickOnceDoUpdate();
        }

        void appDeployement_UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
        {
            frmProgressBar.ProgressChanged("Downloading " + (int)(e.BytesCompleted / 1024) + "/" + (int)(e.BytesTotal / 1024) + "KB", e.ProgressPercentage);
        }

        void appDeployement_UpdateCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (frmProgressBar != null) frmProgressBar.Close();
            frmProgressBar = null;
            Cursor.Current = Cursors.Default;
            MessageBox.Show("The application has been upgraded, and will now restart.", ProductName);
            Application.Restart();
        }


        #endregion

        #region DB

        private void GetUpdateAppInfoDB()
        {
            string appInfoFromWeb = Path.Combine(_dataDirectory, APPINFOWEB_DB);
            try
            {
                SaveAppInfoDB();
                Cursor.Current = Cursors.WaitCursor;
                HttpWebRequest request = Utils.CreateHttpWebRequest(URL_APPINFO_DB, ProductName + " " + ProductVersion, _proxy);
                using (WebResponse response = request.GetResponse())
                {
                    using (StreamReader sr = new StreamReader(response.GetResponseStream()))
                    {
                        string content = sr.ReadToEnd();
                        if (!string.IsNullOrEmpty(content))
                        {
                            if (content.Split('\n').Length > 5)
                                File.WriteAllText(appInfoFromWeb, content);
                        }
                        sr.Close();
                    }
                    response.Close();
                }
            }
            catch (Exception)
            {
            }

            try
            {
                if (File.Exists(appInfoFromWeb))
                {
                    AppInfos appInfosWeb = new AppInfos();
                    appInfosWeb.Load(appInfoFromWeb);
                    _appInfos.Merge(appInfosWeb);
                    SaveAppInfoDB();
                }
                _appInfos.Load(Path.Combine(_dataDirectory, APPINFO_DB));
            }
            catch (Exception)
            {
            }
            Cursor.Current = Cursors.Default;

        }

        private void SaveAppInfoDB()
        {
            _appInfos.Save(Path.Combine(_dataDirectory, APPINFO_DB));
        }

        #endregion

        #region DB UI

        private void updateDetectionListOnStartToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            Settings.Default.AutoUpdateDBOnStart = updateDetectionListOnStartToolStripMenuItem.Checked;
            Settings.Default.Save();
        }

        private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewUsage.SelectedItems.Count > 0)
            {
                AppInfoProperties appInfoProperties = new AppInfoProperties((AppInfo)listViewUsage.SelectedItems[0].Tag);
                if (appInfoProperties.ShowDialog() == DialogResult.OK)
                {
                    SaveAppInfoDB();
                    ListViewGroup group = MakeGroup(((AppInfo)listViewUsage.SelectedItems[0].Tag).Category);
                    MoveItemToGroup(listViewUsage.SelectedItems[0], group);
                    RefreshListViewItem((AppInfo)listViewUsage.SelectedItems[0].Tag, listViewUsage.SelectedItems[0]);
                    RefreshGroupTime(group);
                }
            }
        }


        private void updateDetectionListnowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GetUpdateAppInfoDB();
            BindListView();
        }

        #endregion

        #region ListView
        private void RefreshListViewItem(AppInfo appInfo, ListViewItem currentAppItem)
        {
            currentAppItem.Name = appInfo.GetHashCode().ToString();
            currentAppItem.Text = appInfo.ShortName;
            currentAppItem.Checked = appInfo.Monitored;
            currentAppItem.Group = MakeGroup(appInfo.Category);
            currentAppItem.Tag = appInfo;
            if (currentAppItem.SubItems.Count == 1)
            {
                for (int i = 0; i < listViewUsage.Columns.Count; i++)
                {
                    currentAppItem.SubItems.Add("");
                }
            }
            if ((int)currentAppItem.Group.Tag == 0)
                currentAppItem.Group.Tag = appInfo.Usage;
            currentAppItem.SubItems[columnHeaderAppName.Index].Text = appInfo.Name;
            currentAppItem.SubItems[columnHeaderFilePattern.Index].Text = appInfo.FileName;
            currentAppItem.SubItems[columnHeaderTitlePattern.Index].Text = appInfo.TitlePattern;
            currentAppItem.SubItems[columnHeaderTitle.Index].Text = appInfo.CurrentTitle;
            currentAppItem.SubItems[columnHeaderShortName.Index].Text = appInfo.ShortName;
            currentAppItem.SubItems[columnHeaderUsage.Index].Text = new TimeSpan(0, 0, appInfo.Usage).ToString();
        }

        private ListViewItem CreateListViewItem(AppInfo appInfo)
        {
            ListViewItem currentAppItem = new ListViewItem(appInfo.GetHashCode().ToString(), 0);
            RefreshListViewItem(appInfo, currentAppItem);
            return currentAppItem;
        }

        private void BindListView()
        {
            listViewUsage.SuspendLayout();
            listViewUsage.BeginUpdate();
            listViewUsage.ShowGroups = !bTweetAppName.Checked;
            listViewUsage.ItemChecked -= listViewUsage_ItemChecked;
            listViewUsage.Items.Clear();
            listViewUsage.Groups.Clear();
            ListViewGroup groupOthers = listViewUsage.Groups.Add(AppInfo.OTHERS_CATEGORY_NAME, AppInfo.OTHERS_CATEGORY_NAME);
            groupOthers.Tag = 0;
            Groups.Clear();
            Groups.Add(groupOthers.Name, groupOthers);

            foreach (AppInfo appInfo in _appInfos)
            {
                MakeGroup(appInfo.Category);
            }

            foreach (AppInfo appInfo in _appInfos)
            {
                if (bShowDetectionList.Checked || (appInfo.Monitored && appInfo.Usage > Settings.Default.UsageBeforeShow))
                {
                    listViewUsage.Items.Add(CreateListViewItem(appInfo));
                }
            }
            foreach (ListViewGroup group in listViewUsage.Groups)
            {
                RefreshGroupTime(group);
            }
            listViewUsage.Sort();
            listViewUsage.ItemChecked += listViewUsage_ItemChecked;
            listViewUsage.EndUpdate();
            listViewUsage.ResumeLayout();
        }

        private ListViewGroup MakeGroup(string pGroupName)
        {
            if (!Groups.ContainsKey(pGroupName))
            {
                ListViewGroup group = listViewUsage.Groups.Add(pGroupName, pGroupName);
                group.Tag = 0;
                Groups.Add(group.Name, group);
                return group;
            }
            else
                return Groups[pGroupName];
        }

        private void RefreshGroupTime(ListViewGroup group)
        {
            group.Tag = 0;
            foreach (ListViewItem item in group.Items)
            {
                group.Tag = ((int)group.Tag) + ((AppInfo)item.Tag).Usage;
            }
        }

        private void MoveSelectedToGroup(ListViewGroup group)
        {
            foreach (ListViewItem item in listViewUsage.SelectedItems)
            {
                MoveItemToGroup(item, group);
            }
            RefreshGroupTime(group);
            listViewUsage.Refresh();
        }

        private void MoveItemToGroup(ListViewItem item, ListViewGroup group)
        {
            //// move to the same group (using rename)
            if (group.Items.Contains(item))
                return;
            // move to the same group (using move)
            if (item.Group != null)
                item.Group.Items.Remove(item);
            group.Items.Add(item);
            ((AppInfo)item.Tag).Category = group.Name;
        }

        #endregion

        #region Settings

        private void SaveAll()
        {
            SaveSettings();
            SaveAppInfoDB();
        }

        private void SaveSettings()
        {
            if (txtTwitterLogin.Tag != null)
                Settings.Default.TwitterLogin = txtTwitterLogin.Text;
            if (txtTwitterPassword.Tag != null)
                Settings.Default.TwitterPassword = txtTwitterPassword.Text;
            if (txtTwitterLogin.Tag != null || txtTwitterPassword != null)
            {
                txtTwitterLogin.Tag = null;
                txtTwitterPassword.Tag = null;
                Settings.Default.Save();
            }
        }

        private void LoadSettings()
        {
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                _dataDirectory = _appDeployement.DataDirectory + "/";
            }
            _proxy = WebRequest.GetSystemWebProxy();
            _proxy.Credentials = CredentialCache.DefaultCredentials;

            if (Settings.Default.UpgrageSettingsThroughVersions)
            {
                Settings.Default.Upgrade();
                Settings.Default.UpgrageSettingsThroughVersions = false;
                Settings.Default.Save();
            }
            if (Settings.Default.InstallationDate < new DateTime(1900, 1, 1))
                Settings.Default.InstallationDate = DateTime.Now;
            timer.Interval = REFRESH_INTERVAL * 1000;

            SetMinimumUsageThreshold(new Duration(Settings.Default.UsageBeforeTweet));
            setlowestUsageColorToolStripMenuItem.Image = new Bitmap(2, 2);
            sethighestUsageColorToolStripMenuItem.Image = new Bitmap(2, 2);
            using (Graphics g = Graphics.FromImage(setlowestUsageColorToolStripMenuItem.Image))
            {
                g.Clear(Settings.Default.ChartMinColor);
            }
            using (Graphics g = Graphics.FromImage(sethighestUsageColorToolStripMenuItem.Image))
            {
                g.Clear(Settings.Default.ChartMaxColor);
            }
            updateDetectionListOnStartToolStripMenuItem.Checked = Settings.Default.AutoUpdateDBOnStart;
            bTweetAppName.Checked = Settings.Default.TweetApplicationsName;
            txtTwitterLogin.Text = Settings.Default.TwitterLogin;
            txtTwitterPassword.Text = Settings.Default.TwitterPassword;
            SetLastTweetDate(Settings.Default.LastTweetDate, Settings.Default.LastTweetUrl);
            if (ApplicationDeployment.IsNetworkDeployed && _appDeployement.IsFirstRun)
            {
                TipTopToolAboutBox aboutBox = new TipTopToolAboutBox();
                aboutBox.ShowDialog();
            }

        }

        private void bTweetAppName_CheckedChanged(object sender, EventArgs e)
        {
            RefreshUsageResult(true);
            Settings.Default.TweetApplicationsName = bTweetAppName.Checked;
            Settings.Default.Save();
            BindListView();
        }

        private void alwaysOnTopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.TopMost = alwaysOnTopToolStripMenuItem.Checked;
        }

        private void showInTaskBarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.ShowInTaskbar = showInTaskBarToolStripMenuItem.Checked;
        }
        #endregion

        #region Include/Exclude

        private void listViewUsage_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            AppInfo appInfo = (AppInfo)e.Item.Tag;
            appInfo.Monitored = e.Item.Checked;
            RefreshGroupTime(e.Item.Group);
            if (sender == listViewUsage)
                SaveAppInfoDB();
        }

        private void monitorUsageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int idx = 0;
            while (listViewUsage.SelectedItems.Count > idx)
            {
                listViewUsage.SelectedItems[idx].Checked = monitorUsageToolStripMenuItem.Checked;
                listViewUsage_ItemChecked(sender, new ItemCheckedEventArgs(listViewUsage.SelectedItems[idx]));
                if (!bShowDetectionList.Checked && !listViewUsage.SelectedItems[idx].Checked)
                    listViewUsage.Items.Remove(listViewUsage.SelectedItems[idx]);
                else
                    idx++;
            }
            SaveAppInfoDB();
        }

        #endregion

        #region AppInfo UI

        #region Group UI
        void newGroupNameMenuItem_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
            {
                newGroupNameMenuItem_Validated(sender, e);
                e.Handled = true;
            }
        }

        void renameGroupNameMenuItem_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
            {
                renameGroupNameMenuItem_Validated(sender, e);
                e.Handled = true;
            }

        }

        void renameGroupNameMenuItem_Validated(object sender, EventArgs e)
        {
            if (sender is ToolStripTextBox)
            {
                ToolStripTextBox renameGroupNameMenuItem = (ToolStripTextBox)sender;
                ListViewItem item = listViewUsage.SelectedItems.Count == 0 ? null : listViewUsage.SelectedItems[0];
                if (item != null)
                {
                    ListViewGroup oldGroup = item.Group;
                    if (oldGroup.Name == renameGroupNameMenuItem.Text)
                        return;
                    if (!Groups.ContainsKey(renameGroupNameMenuItem.Text))
                    {
                        oldGroup.Name = renameGroupNameMenuItem.Text;
                        oldGroup.Header = renameGroupNameMenuItem.Text;
                    }
                    else
                    {
                        listViewUsage.Groups.Remove(oldGroup);
                        Groups.Remove(oldGroup.Name);
                    }
                    MoveSelectedToGroup(item.Group);
                    item.EnsureVisible();
                }
            }
        }

        void newGroupNameMenuItem_Validated(object sender, EventArgs e)
        {
            if (sender is ToolStripTextBox)
            {
                ToolStripTextBox newGroupNameMenuItem = (ToolStripTextBox)sender;
                ListViewGroup group = MakeGroup(newGroupNameMenuItem.Text);
                MoveSelectedToGroup(group);
                if (Groups[newGroupNameMenuItem.Text].Items.Count > 0)
                    Groups[newGroupNameMenuItem.Text].Items[0].EnsureVisible();
            }
        }
        #endregion

        private void btnResetUsage_Click(object sender, EventArgs e)
        {
            if (listViewUsage.SelectedItems.Count == 0)
            {
                if (MessageBox.Show("Do you want to reset usage for all applications ?", ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                {
                    foreach (ListViewItem item in listViewUsage.Items)
                    {
                        item.Selected = true;
                    }
                }
                else return;
            }
            if (listViewUsage.SelectedItems.Count > 0)
            {
                foreach (ListViewItem item in listViewUsage.SelectedItems)
                {
                    AppInfo appInfo = (AppInfo)item.Tag;
                    appInfo.Usage = 0;
                    RefreshListViewItem(appInfo, item);
                    RefreshGroupTime(item.Group);
                }
            }
            RefreshUsageResult(true);
            BindListView();
        }

        private void contextMenuStripAppInfo_Opening(object sender, CancelEventArgs e)
        {
            ListViewItem item = listViewUsage.SelectedItems.Count == 0 ? null : listViewUsage.SelectedItems[0];
            if (item != null)
            {
                groupToolStripMenuItem.DropDownItems.Clear();
                monitorUsageToolStripMenuItem.Checked = ((AppInfo)item.Tag).Monitored;
                ToolStripMenuItem newGroupMenuItem = (ToolStripMenuItem)groupToolStripMenuItem.DropDownItems.Add("Move to new group'...");
                ToolStripTextBox newGroupNameMenuItem = new ToolStripTextBox("NewGroup");
                newGroupMenuItem.DropDownItems.Add(newGroupNameMenuItem);
                newGroupNameMenuItem.Text = item.Group.Name;
                newGroupNameMenuItem.KeyDown += new KeyEventHandler(newGroupNameMenuItem_KeyDown);

                if (item.Group != null)
                {
                    ToolStripMenuItem renameGroupMenuItem = (ToolStripMenuItem)groupToolStripMenuItem.DropDownItems.Add("Rename '" + item.Group.Name + "' to ...");
                    ToolStripTextBox renameGroupNameMenuItem = new ToolStripTextBox("RenameGroup");
                    renameGroupNameMenuItem.Text = item.Group.Name;
                    renameGroupMenuItem.DropDownItems.Add(renameGroupNameMenuItem);
                    renameGroupNameMenuItem.KeyDown += new KeyEventHandler(renameGroupNameMenuItem_KeyDown);
                }
                foreach (ListViewGroup group in listViewUsage.Groups)
                {
                    ToolStripItem contextMenuStripMoveToGroup = groupToolStripMenuItem.DropDownItems.Add(group.Name);
                    contextMenuStripMoveToGroup.Tag = group;
                    contextMenuStripMoveToGroup.Click += new EventHandler(contextMenuStripMoveToGroup_Click);
                }
            }
            else
                e.Cancel = true;
        }

        private void contextMenuStripMoveToGroup_Click(object sender, EventArgs e)
        {
            if (((ToolStripItem)sender).Tag != null)
            {
                ListViewGroup group = (ListViewGroup)((ToolStripItem)sender).Tag;
                MoveSelectedToGroup(group);
            }
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            listViewUsage.SuspendLayout();
            while (listViewUsage.SelectedItems.Count > 0)
            {
                _appInfos.Remove((AppInfo)listViewUsage.SelectedItems[0].Tag);
                listViewUsage.Items.Remove(listViewUsage.SelectedItems[0]);
            }
            listViewUsage.ResumeLayout();
        }

        private void resetUsageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            btnResetUsage_Click(sender, e);
        }

        private void listViewUsage_DoubleClick(object sender, EventArgs e)
        {
            if (!bShowDetectionList.Checked)
                propertiesToolStripMenuItem_Click(sender, e);
        }

        private void bShowDetectionList_CheckedChanged(object sender, EventArgs e)
        {
            listViewUsage.SuspendLayout();
            if (bShowChart.Checked)
            {
                listViewUsage.Visible = true;
                bShowChart.CheckedChanged -= bShowChart_CheckedChanged;
                bShowChart.Checked = false;
                bShowChart.CheckedChanged += bShowChart_CheckedChanged;

                bShowDetectionList.CheckedChanged -= bShowDetectionList_CheckedChanged;
                bShowDetectionList.Checked = false;
                bShowDetectionList.CheckedChanged += bShowDetectionList_CheckedChanged;
            }
            if (bShowDetectionList.BackgroundImage != null)
                bShowDetectionList.BackgroundImage.Dispose();
            bShowDetectionList.BackgroundImage = bShowDetectionList.Checked ? Resources.appfinder_128x128 : Resources.apptimer_128x128;
            listViewUsage.ItemChecked -= listViewUsage_ItemChecked;
            listViewUsage.CheckBoxes = bShowDetectionList.Checked;
            listViewUsage.ItemChecked += listViewUsage_ItemChecked;
            listViewUsage.ResumeLayout();
            BindListView();
        }

        #endregion

        #region Chart

        private void bShowChart_CheckedChanged(object sender, EventArgs e)
        {
            // UI trick to display something even when creating chart
            listViewUsage.Visible = true;
            imgChart.Visible = bShowChart.Checked;
            if (bShowChart.Checked)
            {
                bShowDetectionList.CheckedChanged -= bShowDetectionList_CheckedChanged;
                bShowDetectionList.Checked = false;
                bShowDetectionList.CheckedChanged += bShowDetectionList_CheckedChanged;
                if (bShowDetectionList.BackgroundImage != null)
                    bShowDetectionList.BackgroundImage.Dispose();
                bShowDetectionList.BackgroundImage = bShowDetectionList.Checked ? Resources.appfinder_128x128 : Resources.apptimer_128x128;
                RefreshUsageResult(true);
            }
            listViewUsage.Visible = !bShowChart.Checked;
        }

        private void BuildUsageChart(object newChartUrl)
        {
            BuildUsageChart(newChartUrl, imgChart);
        }

        private void BuildUsageChart(object newChartUrl, PictureBox pictureBox)
        {
            if (pictureBox.Visible && newChartUrl != pictureBox.Tag)
            {
                pictureBox.Tag = newChartUrl;
            }
            lock (pictureBox)
            {
                Bitmap tmpImg = null;
                string sUsageChartUrl = newChartUrl as string;
                try
                {
                    if (string.IsNullOrEmpty(sUsageChartUrl))
                    {
                        if (pictureBox.Image != null)
                        {
                            pictureBox.Image.Dispose();
                            pictureBox.Image = null;
                        }
                        pictureBox.Image = Resources.TweetMyApps;
                        return;
                    }
                    HttpWebRequest request = Utils.CreateHttpWebRequest(sUsageChartUrl, ProductName + " " + ProductVersion, _proxy);
                    using (WebResponse response = request.GetResponse())
                    {
                        using (Stream sr = response.GetResponseStream())
                        {
                            tmpImg = (Bitmap)Image.FromStream(sr);
                            sr.Close();
                        }
                        response.Close();
                    }
                    if (tmpImg != null)
                    {
                        pictureBox.SuspendLayout();
                        if (pictureBox.Image != null)
                        {
                            pictureBox.Image.Dispose();
                            pictureBox.Image = null;
                        }
                        pictureBox.Image = tmpImg;
                        tmpImg = null;
                    }
                }
                catch
                {
                    if (tmpImg != null)
                    {
                        tmpImg.Dispose();
                        tmpImg = null;
                    }
                    if (pictureBox.Image != null)
                    {
                        pictureBox.Image.Dispose();
                        pictureBox.Image = null;
                    }
                    pictureBox.Image = Resources.TweetMyApps;
                }
                pictureBox.ResumeLayout();
            }
        }

        private void copyImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetImage(imgChart.Image);
        }

        private void copyChartURLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(imgChart.Tag as string)) return;
            Clipboard.SetText(imgChart.Tag as string, TextDataFormat.Text);
        }

        private void copytweetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(lblUsageTweet.Text, TextDataFormat.Text);
        }

        private void setlowestUsageColorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            colorDialog.Color = setlowestUsageColorToolStripMenuItem.BackColor;
            if (colorDialog.ShowDialog() == DialogResult.OK)
            {
                using (Graphics g = Graphics.FromImage(setlowestUsageColorToolStripMenuItem.Image))
                {
                    g.Clear(colorDialog.Color);
                }
                Settings.Default.ChartMinColor = colorDialog.Color;
                RefreshUsageResult(true);
            }
        }

        private void sethighestUsageColorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            colorDialog.Color = sethighestUsageColorToolStripMenuItem.BackColor;
            if (colorDialog.ShowDialog() == DialogResult.OK)
            {
                using (Graphics g = Graphics.FromImage(sethighestUsageColorToolStripMenuItem.Image))
                {
                    g.Clear(colorDialog.Color);
                }
                Settings.Default.ChartMaxColor = colorDialog.Color;
                RefreshUsageResult(true);
            }
        }

        private void b3dChartToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            RefreshUsageResult(true);
        }

        private void refreshChartToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RefreshUsageResult(true);
        }

        #endregion

        #region Tweet
        private void notifyIcon_MouseMove(object sender, MouseEventArgs e)
        {
            RefreshUsageResult();
            string notification = lblUsageTweet.Text;
            if (notification.Length < 64 - ProductName.Length - 3)
                notification = ProductName + ": " + notification;
            notifyIcon.Text = (notification.Length >= 64) ? notification.Remove(60) + "..." : notification;
        }

        private void SetLastTweetDate(DateTime lastTweetDate, string url)
        {
            if (lastTweetDate != null && lastTweetDate > new DateTime(1900, 1, 1))
            {
                Settings.Default.LastTweetDate = lastTweetDate;
                lblLastTweetDate.Text = Settings.Default.LastTweetDate.ToShortDateString() + " " + Settings.Default.LastTweetDate.ToShortTimeString();
            }
            else
            {
                Settings.Default.LastTweetDate = DateTime.MinValue;
                lblLastTweetDate.Text = "Never";
            }
            toolTip.SetToolTip(lblLastTweetDate, url);
            Settings.Default.LastTweetUrl = url;
            if (!string.IsNullOrEmpty(url))
            {
                lblLastTweetDate.Cursor = Cursors.Hand;
                lblLastTweetDate.ForeColor = Color.Blue;
                lblLastTweetDate.Font = new Font(lblLastTweetDate.Font, FontStyle.Underline);
                lblLastTweetDate.Tag = url;
            }
            else
            {
                lblLastTweetDate.Font = new Font(lblLastTweetDate.Font, FontStyle.Regular);
                lblLastTweetDate.Cursor = Cursors.Default;
                lblLastTweetDate.Tag = null;
                lblLastTweetDate.ForeColor = Color.Black;
            }
        }

        private void lblLastTweetDate_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(lblLastTweetDate.Tag as string)) return;
            Process.Start(lblLastTweetDate.Tag as string);
        }

        private void btnTweet_Click(object sender, EventArgs e)
        {
            RefreshUsageResult(true);
            string usage = lblUsageTweet.Text;
            if (string.IsNullOrEmpty(usage))
            {
                MessageBox.Show("Nothing to tweet!\r\nDid you really use your computer?", ProductName);
                return;
            }
            usage = string.Format(Settings.Default.TweetTemplate, usage);
            if (MessageBox.Show("You are going to tweet : \r\n\r\n\"" + usage + "\"\r\n\r\nDo you want to do so ?", ProductName,
                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                Cursor.Current = Cursors.WaitCursor;
                Twitter twitter = new Twitter(txtTwitterLogin.Text, txtTwitterPassword.Text, ProductName);
                twitter.ProxyUri = _proxy.GetProxy(new Uri("http://www.twitter.com")).ToString();
                try
                {
                    TwitterStatus status = twitter.Status.Update(usage);
                    SetLastTweetDate(DateTime.Now, string.Format("http://twitter.com/{0}/status/{1}", status.TwitterUser.UserName, status.ID));
                    SaveSettings();
                    Cursor.Current = Cursors.Default;
                    if (MessageBox.Show("Do you want to reset all your application usages ?", ProductName,
                        MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        _appInfos.ResetAllUsage();
                        SaveAppInfoDB();
                        BindListView();
                    }
                }
                catch (Exception ex)
                {
                    if (!string.IsNullOrEmpty(ex.Message))
                        MessageBox.Show(ex.Message, ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    else if (ex.InnerException != null)
                        MessageBox.Show(ex.InnerException.Message, ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                Cursor.Current = Cursors.Default;
            }
        }

        private void btnTweetChart_Click(object sender, EventArgs e)
        {
            PictureBox img = new PictureBox();
            AppInfos.BuildUsageChart buildUsageChart = delegate(object newChartUrl)
            {
                BuildUsageChart(newChartUrl, img);
            };
            Cursor.Current = Cursors.WaitCursor;
            SetUsageLabel(_appInfos.ComputeUsageResult(bTweetAppName.Checked, true,
                new Size(500, 500), b3dChartToolStripMenuItem.Checked, new AppInfos.BuildUsageChart(buildUsageChart)));
            Cursor.Current = Cursors.Default;
            string usage = lblUsageTweet.Text;
            if (string.IsNullOrEmpty(usage))
            {
                MessageBox.Show("Nothing to tweet!\r\nDid you really use your computer?", ProductName);
                return;
            }
            usage = string.Format(Settings.Default.TweetTemplate, usage);
            if (MessageBox.Show("You are going to tweet : \r\n\r\n\"" + usage + "\"\r\n\r\nDo you want to do so ?", ProductName,
                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                Cursor.Current = Cursors.WaitCursor;
                imgChart.Image.Save(Path.Combine(_dataDirectory, "chart.png"));
                TwiPLi.TwitPicLib twitPic = new TwiPLi.TwitPicLib(txtTwitterLogin.Text, txtTwitterPassword.Text);
                twitPic.UserAgent = ProductName + " " + ProductVersion;
                twitPic.WebProxy = _proxy;
                try
                {
                    TwiPLi.Response response = twitPic.UploadPhoto(Utils.ConvertImageToByteArray(imgChart.Image, ImageFormat.Png), usage, "chart.png");
                    if (response.Status)
                    {
                        SetLastTweetDate(DateTime.Now, response.MediaUrl);
                        SaveSettings();
                        Cursor.Current = Cursors.Default;
                        if (MessageBox.Show("Do you want to reset all your application usages ?", ProductName,
                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                        {
                            _appInfos.ResetAllUsage();
                            SaveAppInfoDB();
                            BindListView();
                        }
                    }
                    else
                        throw new InvalidOperationException(response.ErrorMessage + " (" + response.ErrorCode + ")");
                }
                catch (Exception ex)
                {
                    if (!string.IsNullOrEmpty(ex.Message))
                        MessageBox.Show(ex.Message, ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    else if (ex.InnerException != null)
                        MessageBox.Show(ex.InnerException.Message, ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                Cursor.Current = Cursors.Default;
            }
        }

        private void toolStripComboBoxMinimumUsageThreshold_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetMinimumUsageThreshold((Duration)toolStripComboBoxMinimumUsageThreshold.SelectedItem);
            RefreshUsageResult(true);
        }

        private void toolStripComboBoxMinimumUsageThreshold_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                SetMinimumUsageThreshold(new Duration(toolStripComboBoxMinimumUsageThreshold.Text));
                RefreshUsageResult(true);
                e.Handled = true;
            }
        }

        private void SetMinimumUsageThreshold(Duration duration)
        {
            toolStripComboBoxMinimumUsageThreshold.SelectedIndexChanged -= toolStripComboBoxMinimumUsageThreshold_SelectedIndexChanged;
            Settings.Default.UsageBeforeTweet = duration;
            int insertPoint = -1;
            foreach (object item in toolStripComboBoxMinimumUsageThreshold.Items)
            {
                insertPoint = toolStripComboBoxMinimumUsageThreshold.Items.IndexOf(item);
                if (duration.Equals((Duration)item))
                {
                    toolStripComboBoxMinimumUsageThreshold.SelectedItem = item;
                    break;
                }
                else if ((Duration)item < duration)
                    continue;
                else if ((Duration)item > duration)
                {
                    toolStripComboBoxMinimumUsageThreshold.Items.Insert(insertPoint, duration);
                    toolStripComboBoxMinimumUsageThreshold.SelectedItem = duration;
                    break;
                }
            }
            if (insertPoint != -1 && !duration.Equals((Duration)toolStripComboBoxMinimumUsageThreshold.SelectedItem))
            {
                toolStripComboBoxMinimumUsageThreshold.Items.Add(duration);
                toolStripComboBoxMinimumUsageThreshold.SelectedItem = duration;
            }
            toolStripComboBoxMinimumUsageThreshold.SelectedIndexChanged += toolStripComboBoxMinimumUsageThreshold_SelectedIndexChanged;
        }

        private void RefreshUsageResult()
        {
            RefreshUsageResult(false);
        }

        private void RefreshUsageResult(bool forced)
        {
            this.Cursor = Cursors.WaitCursor;
            SetUsageLabel(_appInfos.ComputeUsageResult(bTweetAppName.Checked, forced,
                new Size(Math.Min(imgChart.Width, 500), Math.Min(imgChart.Width, 500)), b3dChartToolStripMenuItem.Checked, new AppInfos.BuildUsageChart(BuildUsageChart)));
            this.Cursor = Cursors.Default;
        }

        private void SetUsageLabel(string usage)
        {
            if (string.IsNullOrEmpty(usage))
                usage = "Nothing to tweet";
            lblUsageTweet.Text = usage;
            toolTip.SetToolTip(imgChart, lblUsageTweet.Text);
        }
        #endregion

        private void timer_Tick(object sender, EventArgs e)
        {
            if (IsScreenSaverRunning()) return;
            AppInfo appInfo = _appInfos.GetAppInfo(GetActiveApplicationTitle(), GetActiveApplicationFileName().ToLower());
            if (appInfo == null) return;
            appInfo.Usage = ((int)appInfo.Usage) + timer.Interval / 1000;
            if (string.IsNullOrEmpty(appInfo.ShortName) || appInfo.ShortName == "Unknown"
                || (!appInfo.Monitored && !bShowDetectionList.Checked))
                return;
            if (appInfo.Usage > Settings.Default.UsageBeforeShow)
            {
                ListViewItem[] appItems = listViewUsage.Items.Find(appInfo.GetHashCode().ToString(), true);
                ListViewItem currentAppItem = null;
                if (appItems.Length == 0)
                {
                    currentAppItem = listViewUsage.Items.Add(CreateListViewItem(appInfo));
                }
                else
                {
                    currentAppItem = appItems[0];
                    RefreshListViewItem(appInfo, currentAppItem);
                }
                if (currentAppItem.Group != null)
                    currentAppItem.Group.Tag = ((int)currentAppItem.Group.Tag) + timer.Interval / 1000;
                listViewUsage.Refresh();
            }
        }

    }
}

